import {Service} from 'egg';
import * as moment from 'moment';
import * as config from '../../config.json';
import {CallSheet} from '../../typings';

/**
 * 账户：1
 * 服务号：1
 * 技能组：2轮流（仅限呼入） 随机
 * 座席：5（轮流）
 * 通话标签：6随机
 * 满意度：满意8、一般1、差1
 * 服务品质：优5、良1、差1
 * 通话类型状态：呼入接听（普通13转接1）14、ivr5、振铃未接3、排队（时长1s-20s随机，1个放弃1个没放弃）2、黑名单1、并发限制1、呼出接听（普通9转接1）10、呼出未接1、外呼失败1
 * 排队（时长1s-20s随机
 * 振铃时长：1s-20s随机
 * 通话时长：10-300s随机
 * 客户：10个随机
 * 未知客户：3个
 * 省市：随机
 * 排队总数：
 * 定时：9-12点：每隔500+100以内随机数；13-18点：每隔500-100以内随机数生成一条通话。
 *
 * 数据：先造1个月历史数据，剩余的实时造
 * 这个账户只生成假数据，不要有真实数据产生以免造成问题
 */

// @ts-ignore
const INTERVAL = 1000;
// const TABLE = 'N00000000123_c5_call_sheet';
const TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
const WORKTIME = config.work_time;
const INTERVALTIME = config.float_time;
// const DBNAME = 'cc_data_20181114';

export default class CdrMockService extends Service {
  async initMockData(): Promise<any> {
    const {app, ctx} = this;
    ctx.logger.info('my config: ', app.constants.config);
    (this.app.mock.account as any) = app.constants.config.account;
    // 分库
    const accountDoc = await app.commonDB.db('bill').collection('platform_account_product')
      .findOne({_id: app.mock.account + '_cc'}, {fields: {dataDB: 1}});
    ctx.logger.info('账户信息：', accountDoc);
    (this.app.mock.dataDB as any) = accountDoc.dataDB;
    (this.app.mock.table as any) = app.mock.account + '_c5_call_sheet';
    // 服务号
    const serviceNo = await app.commonDB.db('cc').collection('manager_ivr_service_no').findOne({Account: app.mock.account});
    ctx.logger.info('取到的服务号：', serviceNo);
    (this.app.mock.serviceNo as any) = serviceNo.Exten;
    // 呼叫类型
    (this.app.mock.connect_types as any) = ['dialout', 'dialout', 'dialout', 'dialout', 'dialout', 'dialout', 'dialout', 'dialout', 'dialout',
      'normal', 'normal', 'normal', 'normal', 'normal', 'normal', 'normal', 'normal', 'normal', 'normal', 'normal', 'normal', 'normal',
      'dialTransfer', 'transfer'];
    (this.app.mock.status_dialout as any) = ['dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing',
      'notDeal', 'leak', 'blackList'];
    (this.app.mock.status_normal as any) = ['dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing',
      'notDeal', 'notDeal', 'notDeal',
      'leak', 'leak', 'leak', 'leak', 'leak', 'leak',
      'queueLeak', 'queueLeak', 'voicemail', 'limit', 'blackList'];
    (this.app.mock.status_trans as any) = ['dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'dealing', 'notDeal'];
    // 满意度选项 INVESTIGATE
    (this.app.mock.investigates as any) = ['1', '2', '3'];
    // 省份选项 PROVINCE PROVINCE_CODE
    (this.app.mock.address as any) = require('../../district.json');
    // 转接状态选项 TRANSFER_MODE
    (this.app.mock.transfer_modes as any) = ['num', 'skillgroup'];
    // 服务品质标签 SQ_LABEL
    const sqls: any = await app.commonDB.db().collection('manager_service_quality_call_label')
      .find({accountId: app.mock.account, enable: true}).toArray();
    ctx.logger.info('取到的服务品质标签数：', sqls.length);
    (this.app.mock.sqlids as any) = sqls.map((e) => {
      return e._id;
    });
    // 通话标签 LABELS
    const labels: any = await app.commonDB.db().collection('manager_call_label')
      .find({accountId: app.mock.account, type: 'multi'}).toArray();
    ctx.logger.info('取到的通话标签数：', labels.length);
    (this.app.mock.labels as any) = labels.map((e) => {
      return e._id + '@';
    });
    const customers: any = await this.app.commonDB.db(app.mock.dataDB).collection(app.mock.account + '_customer').find({}, {limit: 10}).toArray();
    ctx.logger.info('取到的客户数：', customers.length);
    const cusArr: any = [];
    customers.forEach((e) => {
      if (e.phone && e.phone.length && e.phone[0].tel) {
        cusArr.push({name: e.name, _id: e._id, phone: e.phone[0].tel});
      } else {
        app.logger.error('客户没有电话');
      }
    });
    cusArr.push({name: '未知客户', _id: ''});
    cusArr.push({name: '未知客户', _id: ''});
    cusArr.push({name: '未知客户', _id: ''});
    (this.app.mock.customers as any) = cusArr;
    // 初始化技能组
    const peers = await app.commonDB.db().collection('manager_ivr_skillgroup')
      .find({Account: app.mock.account, isdel: {$ne: true}}, {fields: {Exten: 1, PBX: 1, DisplayName: 1}}).toArray();
    ctx.logger.info('取到的技能组：', peers.length);
    if (peers.length) {
      app.mock.pbx = peers[0].PBX;
    }
    (app.mock.peers as any) = peers.map((e) => {
      return {
        Exten: e.Exten,
        name: e.DisplayName,
      };
    });
    // 初始化坐席
    const users: any = await app.commonDB.db('bill').collection('platform_user').find({account: app.mock.account}).toArray();
    ctx.logger.info('取到的坐席数：', users.length);
    (this.app.mock.agents as any) = users.map((e) => {
      return e._id;
    });
  }

  // 开始执行任务
  async startMock(): Promise<any> {
    const {app} = this;
    try {
      const _currentTime = moment();
      const _currentHours = _currentTime.hour();
      const _currentUnix = _currentTime.toDate().getTime();
      if (WORKTIME.indexOf(_currentHours) > -1) {
        // 9-12点：每隔(300+100)s以内随机数；13-18点：每隔(300-100)s以内随机数 生成时间
        const ranNum = this.randomNumber(100, 0) * 1000;
        const _beginTime = _currentHours > 12 ? moment(_currentUnix - ranNum).format(TIME_FORMAT) : moment(_currentUnix + ranNum).format(TIME_FORMAT);
        const docs = await this.getMockData(_beginTime);
        await this.insertOne(docs);
      }
    } catch (error) {
      app.logger.error('mock_error', error);
    } /*finally {
      const hours = new Date().getHours();
      let time = await this.randomTime();
      const morning = this.app.mock.time_solt.filter((key) => key < 3);
      const afternoon = this.app.mock.time_solt.filter((key) => key > 3);
      // @ts-ignore
      if (morning.concat(hours)) {
        time = time + this.randomNumber(100, 0);
        // @ts-ignore
      } else if (afternoon.concat(hours)) {
        time = time - this.randomNumber(100, 0);
      }
      // 检测时间是否退出
      setTimeout(() => {
        // 9-12点：每隔500+100以内随机数；13-18点：每隔500-100以内随机数生成一条通话
        // @ts-ignore
        if (this.app.mock.time_solt.concat(hours)) {
          this.startMock();
        }
      }, time);
    }*/
  }

  async startMockByTime(startTime: string, endTime: string): Promise<any> {
    const {app} = this;
    let count: number = 0;
    try {
      let beginTime: string = startTime;
      let insertArr: CallSheet[] = [];
      // 浮动时间 & 结束时间 时间戳
      let beginUnix: number = moment(beginTime).toDate().getTime();
      const endUnix: number = moment(endTime).toDate().getTime();
      while (beginUnix <= endUnix) {
        // 是否在工作时间
        const beginHour: number = moment(beginTime).toDate().getHours();
        if (WORKTIME.indexOf(beginHour) > -1) {
          const docs: CallSheet = await this.getMockData(beginTime);
          insertArr.push(docs);
          count++;
        }
        if (insertArr.length > INTERVALTIME) {
          await this.insertMany(insertArr);
          insertArr = [];
          app.logger.info('========== 已存 ' + count + ' 条数据========');
        }
        // 9-12点：每隔300+100以内随机数；13-18点：每隔300-100以内随机数 生成时间
        const ranNum = this.randomNumber(100, 0);
        beginTime = beginHour > 12 ? moment(beginTime).add(INTERVALTIME - ranNum, 's').format(TIME_FORMAT) : moment(beginTime).add(INTERVALTIME + ranNum, 's').format(TIME_FORMAT);
        beginUnix = moment(beginTime).toDate().getTime();
      }
      return count;
    } catch (error) {
      app.logger.error('mock_error', error);
    }
  }

  async getMockData(endTime?: string): Promise<any> {
    const {app} = this;
    const id = app.m7Utils.UUID.generateUuid();
    // @ts-ignore
    const doc: CallSheet = {
      _id: id,
      CALL_SHEET_ID: id,
      ACCOUNT_ID: app.mock.account,
      PBX: app.mock.pbx,
      CUSTOMER_ID: '',
      CALL_NO: '',
      STATUS: '',
      DISPOSAL_AGENT: '',
      BEGIN_TIME: '',
      END_TIME: '',
      CALLED_NO: '',
      OFFERING_TIME: '',
      CONNECT_TYPE: '',
      RECORD_FILE_NAME: '',
      CUSTOMER_NAME: '',
      ORIGIN_ID: '',
      REF_CALL_SHEET_ID: '',
      HOLD_TIMES: 0,
      HOLD_TIME_LENGTH: 0,
      IS_AUTO_CALL: false,
      DIRECTION: '',
      ERROR_MEMO: '', // 技能组
      CALL_ID: '',
      LOCATION: '',
      ACTION_ID: '',
      LOGIN_TYPE: '',
      LOCATION_NAME: '',
      QUEUE_TIME_LENGTH: 0,
      LOCATION_ID: '',
      QUEUE_NAME: '',
      QUEUE_TIME: '',
      FILE_SERVER: '',
      STATISTIC: '',
      PROVINCE: '',
      PROVINCE_CODE: '',
      DISTRICT: '',			    // 区
      DISTRICT_CODE: '',		// 区号
      REPEAT_CALL: '',
      CONSULT_TIME_LENGTH: 0,       // 咨询时间
      THREEWAY_CALL_TIME_LENGTH: 0, // 三方通话时长(?)
      MANYQUEUE_NUMBER: '',
      QUICK_QUERY_NUM: '',
      PROCESS_STATUS: 'solved',		// 处理状态	solved(已处理)/pending(待处理)
      CALL_TIME_LENGTH: 0,	// 通话时长
      RING_TIME_LENGTH: 0,	// 振铃时长(从振铃到接听的时间)
      IVR_TIME_LENGTH: 0,	  // IVR通话时长
      biUpdateTime: '',
      HANGUP_USER: '',        // 挂机方
      INVESTIGATE: '',      // 满意度
      SQ_LABEL: '',
    };
    this.processConnectype(doc);
    this.processStatus(doc);
    this.processTimeAndLenth(doc, endTime);
    this.processCustomer(doc);
    this.processAgent(doc);
    this.processPeer(doc); // 技能组
    this.processSatisfied(doc); // 满意度
    this.processTransfer(doc); // 转接处理
    this.processCity(doc); // 生成随机城市
    this.processLabels(doc); // 通话标签
    this.processSqlabel(doc);
    return doc;
  }

  processConnectype(doc: CallSheet) {
    const connectType = this.randomConnectype();
    doc.CONNECT_TYPE = connectType;
  }

  processStatus(doc: CallSheet) {
    const status = this.randomStatus(doc.CONNECT_TYPE);
    doc.STATUS = status;
  }

  processTimeAndLenth(doc: CallSheet, endTime?: string) {
    let momentObj = moment();
    if (endTime) {
      momentObj = moment(endTime, TIME_FORMAT);
    }
    doc.biUpdateTime = momentObj.format(TIME_FORMAT);
    const callLen = this.randomNumber(300, 10);
    const ringLen = this.randomNumber(20, 1);
    const queueLen = this.randomNumber(20, 1);
    if (doc.STATUS === 'dealing') {
      const end = momentObj.format(TIME_FORMAT);
      const begin = momentObj.subtract('seconds', callLen).format(TIME_FORMAT);
      const ring = momentObj.subtract('seconds', callLen + ringLen + queueLen).format(TIME_FORMAT);
      doc.OFFERING_TIME = ring;
      doc.BEGIN_TIME = begin;         // 设置接听时间
      doc.END_TIME = end;             // 设置挂机时间
      doc.CALL_TIME_LENGTH = callLen; // 设置通话时长
      doc.RING_TIME_LENGTH = ringLen; // 振铃时长
      doc.QUEUE_TIME_LENGTH = queueLen; // 排队时长
    } else {
      momentObj = momentObj.subtract('seconds', 160);
      const end = momentObj.format(TIME_FORMAT);
      const ring = momentObj.subtract('seconds', ringLen).format(TIME_FORMAT);
      doc.OFFERING_TIME = ring;
      doc.BEGIN_TIME = null;          // 设置接听时间
      doc.END_TIME = end;             // 设置挂机时间
      doc.RING_TIME_LENGTH = ringLen; // 振铃时长
    }
  }

  processCustomer(doc: CallSheet) {
    const {app} = this;
    const len = app.mock.customers.length;
    const cus: any = app.mock.customers[this.randomNumber(len - 1, 0)];
    if (!cus._id) {
      doc.CUSTOMER_ID = '0000000000000000';
      doc.CUSTOMER_NAME = '未知客户';
    } else {
      doc.CUSTOMER_NAME = cus.name;
      doc.CUSTOMER_ID = cus._id;
      // this.app.logger.info('==============');
      // this.ctx.logger.info('====', cus.name, cus._id);
    }
    if (doc.CONNECT_TYPE === 'normal' || doc.CONNECT_TYPE === 'transfer') {
      doc.CALL_NO = cus.phone ? cus.phone : this.randomPhone();
      doc.CALLED_NO = app.mock.serviceNo;
    } else {
      doc.CALL_NO = app.mock.serviceNo;
      doc.CALLED_NO = cus.phone ? cus.phone : this.randomPhone();
    }
  }

  processAgent(doc: CallSheet) {
    const len = this.app.mock.agents.length;
    const agent = this.app.mock.agents[this.randomNumber(len - 1, 0)];
    if (doc.CONNECT_TYPE === 'dialout' || doc.CONNECT_TYPE === 'dialTransfer') {
      doc.DISPOSAL_AGENT = agent;
    } else {
      if (doc.STATUS === 'dealing' || doc.STATUS === 'notDeal') {
        doc.DISPOSAL_AGENT = agent;
      }
    }
  }

  processPeer(doc: CallSheet) {
    const len = this.app.mock.peers.length;
    const peer: any = this.app.mock.peers[this.randomNumber(len - 1, 0)];
    if (doc.CONNECT_TYPE === 'normal') {
      doc.ERROR_MEMO = peer.Exten;
      doc.LOCATION_ID = peer.Exten;
      doc.LOCATION_NAME = peer.name;
      doc.QUEUE_NAME = peer.name;
    } else {
      doc.ERROR_MEMO = null;
      this.app.logger.info('no peer');
    }
  }

  processSatisfied(doc: CallSheet) {
    const len = this.app.mock.investigates.length;
    doc.INVESTIGATE = this.app.mock.investigates[this.randomNumber(len - 1, 0)];
  }
  processSqlabel(doc: CallSheet) {
    const len = this.app.mock.sqlids.length;
    const rand = this.randomNumber(len - 1, 0);
    doc.SQ_LABEL = this.app.mock.sqlids[rand];
    this.app.logger.info(len, this.app.mock.sqlids, rand, doc.SQ_LABEL);
  }

  processTransfer(doc: CallSheet) {
    const len = this.app.mock.peers.length;
    const peer: any = this.app.mock.peers[this.randomNumber(len - 1, 0)];
    if (doc.CONNECT_TYPE === 'transfer' || doc.CONNECT_TYPE === 'dialTransfer') {
      const agentLen = this.app.mock.agents.length;
      doc.TRANSFER_AGENT = this.app.mock.agents[this.randomNumber(agentLen - 1, 0)];
      const modeLen = this.app.mock.transfer_modes.length;
      doc.TRANSFER_MODE = this.app.mock.transfer_modes[this.randomNumber(modeLen - 1, 0)];
      if (doc.TRANSFER_MODE === 'skillgroup') {
        doc.TRANSFER_NUM = peer.Exten;
        doc.ERROR_MEMO = peer.Exten;
        doc.LOCATION_ID = peer.Exten;
        doc.LOCATION_NAME = peer.name;
        doc.QUEUE_NAME = peer.name;
      } else if (doc.TRANSFER_MODE === 'num') {
        const nLen = this.app.mock.agents.length;
        doc.TRANSFER_NUM = this.app.mock.agents[this.randomNumber(nLen - 1, 0)];
      }
    }
  }

  processCity(doc: CallSheet) {
    const districtObj = require('../../districtMap.json');
    const address: object = this.app.mock.address;
    // @ts-ignore
    const PROVINCE_OBJ: object = address.province;
    const PROVINCE_ARR: any = Object.keys(PROVINCE_OBJ);

    const province = PROVINCE_ARR[this.randomNumber(PROVINCE_ARR.length - 1, 0)];
    if (province) {
      doc.PROVINCE = province;
      doc.PROVINCE_CODE = PROVINCE_OBJ[province];
    }

    const CHILD_DIS: any = districtObj[province];
    const INDEX = this.randomNumber(CHILD_DIS.length - 1, 0);
    const district = CHILD_DIS[INDEX];
    if (district) {
      doc.DISTRICT = district.name;
      doc.DISTRICT_CODE = district.code;
    }
  }

  async processCitys(doc: CallSheet) {
    const res = await this.telToCity(doc.CALL_NO);
    if (res) {
      const [province, district] = res;
      const addData: object = this.app.mock.address;
      // @ts-ignore
      const dis: object = addData.district;
      // @ts-ignore
      const pro: object = addData.province;
      const district1 = dis[district];
      if (district1) {
        doc.DISTRICT = district;
        doc.DISTRICT_CODE = district1;
      }
      const district2 = dis[`${district}市`];
      if (district2) {
        doc.DISTRICT = district + '市';
        doc.DISTRICT_CODE = district2;
      }
      const province1 = pro[province];
      if (province1) {
        doc.PROVINCE = province;
        doc.PROVINCE_CODE = province1;
      }
      const province2 = pro[`${province}省`];
      if (province2) {
        doc.PROVINCE = province + '省';
        doc.PROVINCE_CODE = province2;
      }
      const province3 = pro[`${province}市`];
      if (province3) {
        doc.PROVINCE = province + '市';
        doc.PROVINCE_CODE = province3;
      }
    }
  }

  processLabels(doc: CallSheet) {
    const len = this.app.mock.labels.length;
    doc.LABELS = [this.app.mock.labels[this.randomNumber(len - 1, 0)]];
  }

  // 单条插入数据库
  async insertOne(docs: any): Promise<any> {
    // this.ctx.logger.info(this.app.mock.dataDB, this.app.mock.table);
    // const doc: CallSheet = docs;
    // this.ctx.logger.info('insertData', this.app.constants.config.tag,
    //   doc.CALL_SHEET_ID, doc.OFFERING_TIME, doc.STATUS, doc.CONNECT_TYPE,
    //   doc.QUEUE_NAME, doc.DISPOSAL_AGENT, doc.DISTRICT, doc.CALL_TIME_LENGTH);
    // this.ctx.logger.info('tag: ' + this.app.constants.config.tag);
    if (this.app.constants.config.tag !== 'no') {
      try {
        await this.app.commonDB.db(this.app.mock.dataDB).collection(this.app.mock.table).insertOne(docs);
      } catch (error) {
        this.ctx.logger.error('insert db error', error);
      }
    }
  }

  async insertMany(docs: any): Promise<any> {
    // this.ctx.logger.info(this.app.mock.dataDB, this.app.mock.table);
    this.ctx.logger.info('insertData size: ', docs.length);
    // this.ctx.logger.info('tag: ' + this.app.constants.config.tag);
    try {
      await this.app.commonDB.db(this.app.mock.dataDB).collection(this.app.mock.table).insertMany(docs);
    } catch (error) {
      this.ctx.logger.error('insertMany db error', error);
    }
  }

  // 随机技能组
  async randomMemo(): Promise<string> {
    return '';
  }

  randomPhone(): string {
    const str = '131';
    const randomnum = Math.round(100000000 * Math.random());
    return str + randomnum;
  }

  // 随机坐席
  randomAgent(): string {
    const len = this.app.mock.agents.length;
    const index = this.randomNumber(len - 1, 0);
    return this.app.mock.agents[index];
  }

  // 随机通话标签
  async randomLabel(): Promise<string> {
    return '';
  }

  // 随机满意度
  async randomSatisfied(): Promise<string> {
    return '';
  }

  // 随机服务品质
  async randomQuality(): Promise<string> {
    return '';
  }

  // 随机通话类型
  randomConnectype(): string {
    const len = this.app.mock.connect_types.length;
    const index = this.randomNumber(len - 1, 0);
    return this.app.mock.connect_types[index];
  }

  // 随机通话状态
  randomStatus(connectType: string): string {
    let arr;
    switch (connectType) {
      case 'normal':
        arr = this.app.mock.status_normal;
        break;
      case 'dialout':
        arr = this.app.mock.status_dialout;
        break;
      case 'transfer':
      // @ts-ignore
      case 'dialTransfer':
        arr = this.app.mock.status_trans;
      default:
        break;
    }
    const len = arr.length;
    const index = this.randomNumber(len - 1, 0);
    return arr[index];
  }

  // 随机振铃时长
  async randomWaitLength(): Promise<string> {
    return '';
  }

  // 随机通话时长
  randomNumber(max: number, min: number): number {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }

  // 随机客户id + 未知客户
  randomCustomer(): string {
    return '';
  }

  // 随机省市
  async randomAddress(): Promise<string> {
    return '';
  }

  // 生成下次任务的执行时间
  async randomTime(): Promise<number> {
    return 500;
  }

  // 根据手机号获取归属地
  async telToCity(tel: string) {
    const {ctx} = this;
    if (tel) {
      const url = 'http://mobsec-dianhua.baidu.com/dianhua_api/open/location?tel=' + tel;
      const res = await ctx.m7Http.sendGet(encodeURI(url), {
        timeout: 120000,
        dataType: 'json',
      });
      const detail = res.data.response[`${tel}`] ? res.data.response[`${tel}`].detail : null;
      if (detail) {
        const city = detail.area[0].city;
        const province = detail.province;
        return [province, city];
      }
      return null;
    } else {
      return null;
    }
  }

}
